package com.yami.shop.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.app.dto.DeliveryDto;
import com.yami.shop.bean.app.dto.DeliveryInfoDto;
import com.yami.shop.bean.bo.DeliveryAliInfoBO;
import com.yami.shop.bean.bo.DeliveryAliItemInfoBO;
import com.yami.shop.bean.bo.DeliveryHundredInfoBO;
import com.yami.shop.bean.bo.DeliveryHundredItemInfoBO;
import com.yami.shop.bean.model.Delivery;
import com.yami.shop.bean.vo.DeliveryOrderVO;
import com.yami.shop.common.bean.Quick100;
import com.yami.shop.common.bean.QuickAli;
import com.yami.shop.common.bean.QuickBird;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.util.DateUtils;
import com.yami.shop.common.util.Json;
import com.yami.shop.config.ShopConfig;
import com.yami.shop.dao.DeliveryMapper;
import com.yami.shop.service.DeliveryService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author lgh on 2018/11/26.
 */
@Service
@AllArgsConstructor
public class DeliveryServiceImpl extends ServiceImpl<DeliveryMapper, Delivery> implements DeliveryService {

    private final ShopConfig shopConfig;
    private final DeliveryMapper deliveryMapper;

    @Override
    public DeliveryDto query(Long dvyId, String expNo, String receiverMobile, String from,String to ) throws UnsupportedEncodingException {
        Delivery delivery = this.getById(dvyId);
        if (Objects.isNull(delivery)) {
            return new DeliveryDto();
        }
        // 快递鸟查询
        QuickBird quickBird = shopConfig.getQuickBird();
        if (Objects.nonNull(quickBird)
                && BooleanUtil.isTrue(quickBird.getIsOpen())
                && !ObjectUtils.isEmpty(delivery.getDvyNo())) {
            return queryByQuickBird(delivery.getDvyNo(), expNo, quickBird, receiverMobile);
        }

        // 快递100查询
        Quick100 quick100 = shopConfig.getQuick100();
        if (Objects.nonNull(quick100)
                && BooleanUtil.isTrue(quick100.getIsOpen())
                && !ObjectUtils.isEmpty(delivery.getDvyNoHd())) {
            return queryByQuick100(delivery.getDvyNoHd(), expNo, quick100, receiverMobile, from, to);
        }

        // 阿里快递查询
        QuickAli aliQuick = shopConfig.getAliQuick();
        if (Objects.nonNull(aliQuick)
                && BooleanUtil.isTrue(aliQuick.getIsOpen())
                && !ObjectUtils.isEmpty(delivery.getAliNo())) {
            return queryByAliQuick(delivery.getAliNo(), expNo, aliQuick, receiverMobile);
        }
        return new DeliveryDto();
    }

    @Override
    public List<DeliveryOrderVO> listDeliveryCountByOrderNumber(List<String> orderNumbers) {
        if (CollUtil.isEmpty(orderNumbers)) {
            return new ArrayList<>();
        }
        return deliveryMapper.listDeliveryCountByOrderNumber(orderNumbers);
    }

    /**
     * 通过快递鸟查询
     *
     * @param expCode 物流公司编码
     * @param expNo   物流单号
     * @param quickBird 快递鸟配置信息
     * @param receiverMobile 收件人手机号
     * @return
     * @throws UnsupportedEncodingException
     */
    private DeliveryDto queryByQuickBird(String expCode, String expNo, QuickBird quickBird, String receiverMobile) throws UnsupportedEncodingException {
        String requestData = "{" +
                "'OrderCode': ''," +
                "'ShipperCode': '" + expCode + "'," +
                "'LogisticCode': '" + expNo + "'," +
                // 快递为顺丰时需要传寄件人/收件人手机号后四位，为其他快递时，可不填或保留字段，不可传值
                "'CustomerName': '" + (Objects.equals(expCode, QuickBird.SF_CODE) ? getLastFourOfMobile(receiverMobile) : "") + "'," +
                "}";
        Map<String, Object> params = new HashMap<String, Object>(16);
        params.put("RequestData", URLEncoder.encode(requestData, "UTF-8"));
        params.put("EBusinessID", quickBird.geteBusinessID());
        String dataSign = Base64.encode(new Digester(DigestAlgorithm.MD5).digestHex(requestData + quickBird.getAppKey()), "UTF-8");
        params.put("DataSign", URLEncoder.encode(dataSign, "UTF-8"));
        params.put("RequestType", "1002");
        params.put("DataType", "2");
        String repJson = HttpUtil.post(quickBird.getReqUrl(), params);
        return JSON.parseObject(repJson, DeliveryDto.class);
    }

    /**
     * 通过快递100查询
     *
     * @param expCode 物流公司编码
     * @param expNo   物流单号
     * @param quick100 快递100配置信息
     * @param receiverMobile 收件人手机号
     * @return
     */
    private DeliveryDto queryByQuick100(String expCode, String expNo, Quick100 quick100, String receiverMobile,String from,String to) {
//        String param = "{\"com\":\"" + expCode + "\",\"num\":\"" + expNo + "\",\"order\":\"asc\"}"; //同下paramMap
        Map<String, Object> paramMap = new HashMap<>(16);
        paramMap.put("com",expCode);
        paramMap.put("num",expNo);
        if(StrUtil.isNotEmpty(from)){
            paramMap.put("from",from);
        }
        if(StrUtil.isNotEmpty(to)){
            paramMap.put("to",to);
        }
        if (Objects.equals(expCode, Quick100.SF_CODE) || Objects.equals(expCode, Quick100.FENGWANG_CODE)) {
            // 快递100中顺丰速运和丰网速运必填收、寄件人手机号码，其他快递公司选填
            paramMap.put("phone", receiverMobile);
        }
        paramMap.put("order","asc");
        String param = JSON.toJSONString(paramMap);
        String sign = new Digester(DigestAlgorithm.MD5).digestHex(param+ quick100.getKey() + quick100.getCustomer(), "UTF-8").toUpperCase();
        Map<String, Object> params = new HashMap<>(16);
        params.put("param", param);
        params.put("sign", sign);
        params.put("customer", quick100.getCustomer());
        String repJson = HttpUtil.post(quick100.getReqUrl(), params);
        // 将查询结果组装成统一对象返回
        DeliveryHundredInfoBO hundredInfoBO = Json.parseObject(repJson, DeliveryHundredInfoBO.class);
        DeliveryDto deliveryInfoVO = new DeliveryDto();
        deliveryInfoVO.setState(hundredInfoBO.getState());
        deliveryInfoVO.setTrailUrl(hundredInfoBO.getTrailUrl());
        if(StrUtil.isNotEmpty(hundredInfoBO.getArrivalTime())){
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh");
            Date parse = null;
            try {
                parse = dateFormat.parse(hundredInfoBO.getArrivalTime());
            } catch (ParseException e) {
                e.printStackTrace();
            }
            deliveryInfoVO.setArrivalTime(parse);
        }

        if(CollectionUtil.isEmpty(hundredInfoBO.getData())){
            deliveryInfoVO.setTraces(new ArrayList<>());
            return deliveryInfoVO;
        }
        List<DeliveryInfoDto> deliveryAliInfoList = new ArrayList<>();
        for (DeliveryHundredItemInfoBO itemInfo : hundredInfoBO.getData()) {
            DeliveryInfoDto deliveryItemInfoVO = new DeliveryInfoDto();
            deliveryItemInfoVO.setAcceptStation(itemInfo.getContext());
            deliveryItemInfoVO.setAcceptTime(itemInfo.getFtime());
            deliveryAliInfoList.add(deliveryItemInfoVO);
        }
        deliveryInfoVO.setTraces(deliveryAliInfoList);
        return deliveryInfoVO;
    }

    /**
     * 通过阿里快递查询,返回当前包裹的快递信息
     *
     * @param expCode 物流公司编码
     * @param expNo   物流单号
     * @param aliQuickConfig 配置信息
     * @param receiverMobile 收件人手机号
     * @return 当前包裹的快递信息
     */
    private DeliveryDto queryByAliQuick(String expCode, String expNo, QuickAli aliQuickConfig, String receiverMobile) {
        Map<String, Object> params = new HashMap<>(16);
        if (Objects.equals(expCode, QuickAli.SF_CODE) && StrUtil.isNotBlank(receiverMobile)) {
            // 使用阿里快递查询时，如果是顺丰单号，需要在单号后面拼接收件人手机号后四位
            expNo = expNo + ":" + getLastFourOfMobile(receiverMobile);
        }
        params.put("type",expCode);
        params.put("no",expNo);
        // params.put("Authorization", "APPCODE" + aliQuickConfig.getAliCode());
        //头信息，多个头信息多次调用此方法即可
        String repJson = HttpRequest.get(aliQuickConfig.getReqUrl())
                .header(Header.AUTHORIZATION, "APPCODE " + aliQuickConfig.getAliCode())
                .form(params)
                .execute().body();
        try {
            String data = JSONObject.parseObject(repJson).getString("result");
            // 将查询结果组装成统一对象返回
            DeliveryAliInfoBO deliveryAliInfoBO = Json.parseObject(data, DeliveryAliInfoBO.class);
            DeliveryDto deliveryInfoVO = new DeliveryDto();
            deliveryInfoVO.setCompanyName(deliveryAliInfoBO.getExpName());
            deliveryInfoVO.setCompanyHomeUrl(deliveryAliInfoBO.getExpSite());
            deliveryInfoVO.setDvyFlowId(deliveryAliInfoBO.getNumber());
            deliveryInfoVO.setState(deliveryAliInfoBO.getDeliverystatus());
            if(CollectionUtil.isEmpty(deliveryAliInfoBO.getList())){
                deliveryInfoVO.setTraces(new ArrayList<>());
                return deliveryInfoVO;
            }
            List<DeliveryInfoDto> deliveryAliInfoList = new ArrayList<>();
            for (DeliveryAliItemInfoBO itemInfo : deliveryAliInfoBO.getList()) {
                DeliveryInfoDto deliveryItemInfoVO = new DeliveryInfoDto();
                deliveryItemInfoVO.setAcceptStation(itemInfo.getStatus());
                deliveryItemInfoVO.setAcceptTime(itemInfo.getTime());
                deliveryAliInfoList.add(deliveryItemInfoVO);
            }
            deliveryInfoVO.setTraces(deliveryAliInfoList);
            return deliveryInfoVO;
        }catch (Exception e){
            log.warn("阿里物流查询错误" + e.getMessage());
            return null;
        }
    }

    private String getLastFourOfMobile(String mobile) {
        // 获取手机号后四位
        if (Objects.isNull(mobile) || mobile.length() < Constant.LAST_FOUR_BY_MOBILE) {
            return "";
        }
        return mobile.substring(mobile.length() - Constant.LAST_FOUR_BY_MOBILE);
    }
}
